package services

import (
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"

	"chat-app/internal/app/models"
	"chat-app/pkg" // 添加配置包
)

type AuthService interface {
	Register(phone, password, nickname string) (*models.User, error)
	Login(phone, password string) (string, error)
	ValidateToken(tokenString string) (uint, error)
}

type authService struct {
	db *gorm.DB
}

func NewAuthService(db *gorm.DB) AuthService {
	// 使用传入的数据库实例
	return &authService{db: db}
}

func (s *authService) Register(phone, password, nickname string) (*models.User, error) {
	var existing models.User

	// 使用事务保证原子性
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 更精确的查询方式
	result := tx.Where("phone = ?", phone).First(&existing)
	if result.RowsAffected > 0 {
		tx.Rollback()
		return nil, errors.New("手机号已被注册")
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	user := models.User{
		Phone:    phone,
		Password: string(hashedPassword),
		Nickname: nickname,
	}

	if err := tx.Create(&user).Error; err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()
	return &user, nil
}
func (s *authService) Login(phone, password string) (string, error) {
	var user models.User

	// 通过手机号查找用户
	if result := s.db.Where("phone = ?", phone).First(&user); result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return "", errors.New("用户不存在")
		}
		return "", result.Error
	}

	// 验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
		return "", errors.New("无效的用户名或密码")
	}

	// 生成JWT token
	secretKey := config.GetJWTSecret()

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"user_id": user.ID,
		"exp":     time.Now().Add(time.Hour * 72).Unix(),
	})

	tokenString, err := token.SignedString([]byte(secretKey))
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

func (s *authService) ValidateToken(tokenString string) (uint, error) {
	secretKey := config.GetJWTSecret()

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("无效的签名方法")
		}
		return []byte(secretKey), nil
	})

	if err != nil {
		return 0, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		userID := uint(claims["user_id"].(float64))
		return userID, nil
	}

	return 0, errors.New("无效的token")
}
